
`include "common_header.verilog"

//  *************************************************************************
//  File : stats_topn_xl
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited. 
//  Copyright (c) 2014 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Daniel Koehler
//  info@morethanip.com
//  *************************************************************************
//  Description : Statistics Registers -- RAM based
//  Version     : $Id: stats_topn_xl.v,v 1.4 2017/04/11 09:06:32 gc Exp $
//  *************************************************************************

module stats_topn_xl (

`ifdef MTIP_SDPM_GEN_GLOBAL_RST
   sdpm_core_reset,
   sdpm_bist_i,
   sdpm_bist_o,
`endif
   reset_rxclk,
   reset_txclk,
   reset_reg_clk,
   rxclk,
   txclk,
   reg_clk,
   reg_rd,
   reg_wr,
   reg_sel,
   reg_data_in,
   stat_data_out,
   stat_rd,
   stat_busy,
   sw_reset,
   sw_reset_done,
   tx_mtu,
`ifdef STAT_PFCCNT_ENA
   tsv_stat_pfc,
   rsv_stat_pfc,
`endif          
   rsv_stat_val,
   rsv_stat,
   frm_align_err,
   tsv_stat_val,
   tsv_stat
`ifdef MTIPSTAT_MEM_EXTERNAL
   ,
   rstm_raddr,
   rstm_rden,
   rstm_rdata,
   rstm_wren,
   rstm_waddr,
   rstm_wdata,
   tstm_raddr,
   tstm_rden,
   tstm_rdata,
   tstm_wren,
   tstm_waddr,
   tstm_wdata
`endif
   );

parameter CNTWIDTH       = 64;
parameter CNTSATURATEOPT = 0;

`ifdef STAT_PFCCNT_ENA
parameter PFC_PRIORITIES = 8; // PFC PRiorities, set to 8 or 16
`endif

`ifdef MTIP_SDPM_GEN_GLOBAL_RST
input   sdpm_core_reset;        // global memory reset for special memories
input   [`MTIP_SDPM_GEN_BIST_I:0] sdpm_bist_i;  // inputs to ALL memories but not necessarily all used in this instance.
output  [`MTIP_SDPM_GEN_BIST_O:0] sdpm_bist_o;  // outputs OR'ed from ALL memories when travelling up the hierarchies
`endif
input   reset_rxclk;            //  Asynchronous Reset - rx_clk Domain
input   reset_txclk;            //  Asynchronous Reset - tx_clk Domain
input   reset_reg_clk;          //  Asynchronous Reset - reg_clk Domain
input   rxclk;                  //  xgmii rx Clock
input   txclk;                  //  xgmii tx Clock
input   reg_clk;                //  ReferenceInterface Clock
input   reg_rd;                 //  Register Read Strobe
input   reg_wr;                 //  Register Write Strobe
input   [7:0] reg_sel;          //  Register Address
input   [31:0] reg_data_in;     //  Write Data from Host Bus
output  [31:0] stat_data_out;   //  Read Data to Host Bus
input   stat_rd;                //  Statistics register address space read access
output  stat_busy;              //  Interface Busy
input   sw_reset;               //  sync reset from command_config clear counters
output  sw_reset_done;          //  clear done
input   [15:0] tx_mtu;          //  Maximum Frame Length (TX)
`ifdef STAT_PFCCNT_ENA
input   [PFC_PRIORITIES-1:0] tsv_stat_pfc;     //  the class enable of latest generated PFC frame
input   [PFC_PRIORITIES-1:0] rsv_stat_pfc;     //  the class enable of latest received PFC frame
`endif
input   rsv_stat_val;           //  Receive Statistic Vector Valid.
input   [31:0] rsv_stat;        //  Receive Statistic Vector.
input   frm_align_err;          //  Received Frame Aligment Error Indication
input   tsv_stat_val;           //  Transmit Statistic Vector Valid.
input   [24:0] tsv_stat;        //  Transmit Statistic Vector   

`ifdef MTIPSTAT_MEM_EXTERNAL

        `ifdef STAT_PFCCNT_ENA
        localparam CNTADDR       = 6;            //  address bits
        `else
        localparam CNTADDR       = 5;            //  address bits
        `endif

output  [CNTADDR-1:0]   rstm_raddr;                     // Stats RX mem Read address (rxclk)
output                  rstm_rden;                      // Stats RX mem read enable (rxclk)
input   [CNTWIDTH+CNTSATURATEOPT-1:0] rstm_rdata;       // Stats RX mem Read data (rxclk)
output                  rstm_wren;                      // Stats RX mem write (rxclk)
output  [CNTADDR-1:0]   rstm_waddr;                     // Stats RX mem write address (rxclk)
output  [CNTWIDTH+CNTSATURATEOPT-1:0] rstm_wdata;       // Stats RX mem write data (rxclk)

wire    [CNTADDR-1:0]   rstm_raddr;
wire                    rstm_rden; 
wire                    rstm_wren; 
wire    [CNTADDR-1:0]   rstm_waddr;
wire    [CNTWIDTH+CNTSATURATEOPT-1:0] rstm_wdata;

output  [CNTADDR-1:0]   tstm_raddr;                     // Stats TX mem Read address (txclk)
output                  tstm_rden;                      // Stats TX mem read enable (txclk)
input   [CNTWIDTH+CNTSATURATEOPT-1:0] tstm_rdata;       // Stats TX mem Read data (txclk)
output                  tstm_wren;                      // Stats TX mem write (txclk)
output  [CNTADDR-1:0]   tstm_waddr;                     // Stats TX mem write address (txclk)
output  [CNTWIDTH+CNTSATURATEOPT-1:0] tstm_wdata;       // Stats TX mem write data (txclk)

wire    [CNTADDR-1:0]   tstm_raddr;
wire                    tstm_rden; 
wire                    tstm_wren; 
wire    [CNTADDR-1:0]   tstm_waddr;
wire    [CNTWIDTH+CNTSATURATEOPT-1:0] tstm_wdata;

`endif


wire    [31:0] stat_data_out; 
wire    stat_busy; 
wire    sw_reset_done; 
wire    stc_clearread;          //  configuration: clear counter on read
wire    stc_saturate;           //  configuration: counters saturate (1) / wrap around (0)
wire    stc_clearall;           //  clear all counters immediately
wire    [CNTWIDTH-1:0] stc_clearvalue; // value to write into memory during clear 
wire    [31:0] stc_data_out;    //  Read Data to Host Bus from control registers
wire    stc_sel;                //  A configuration register address is accessed (stc_data_out is valid)

//  Read rx stats (rxclk domain)
wire    rx_stc_clearread;       //  configuration: clear counter on read
wire    rx_stc_saturate;        //  configuration: counters saturate (1) / wrap around (0)
wire    rx_stats_rd;            //  read request
wire    [7:0] rx_mreg_sel;      //  address in MAC address space
wire    rx_stats_busy;          //  statistics read busy
wire    [CNTWIDTH - 1:0] rx_stats_rdata; // statistics read data return
wire    rx_stats_clear; 
wire    [CNTWIDTH-1:0] rx_stats_clearvalue; // value to write into memory during clear 

//  Read tx stats (txclk domain)
wire    tx_stc_clearread;       //  configuration: clear counter on read
wire    tx_stc_saturate;        //  configuration: counters saturate (1) / wrap around (0)
wire    tx_stats_rd;            //  read request
wire    [7:0] tx_mreg_sel;      //  address in MAC address space
wire    tx_stats_busy;          //  statistics read busy
wire    [CNTWIDTH - 1:0] tx_stats_rdata; // statistics read data return
wire    tx_stats_clear; 
wire    [15:0] tx_mtu_sy;       //  Maximum Frame Length (TX)
wire    [CNTWIDTH-1:0] tx_stats_clearvalue; // value to write into memory during clear 

`ifdef MTIP_SDPM_GEN_GLOBAL_RST
wire    [`MTIP_SDPM_GEN_BIST_O:0] sdpm_bist_o;  // outputs OR'ed from ALL memories when travelling up the hierarchies
wire    [`MTIP_SDPM_GEN_BIST_O:0] sdpm_bist_o0; // outputs OR'ed from ALL memories when travelling up the hierarchies
wire    [`MTIP_SDPM_GEN_BIST_O:0] sdpm_bist_o1; // outputs OR'ed from ALL memories when travelling up the hierarchies
assign  sdpm_bist_o = sdpm_bist_o1;
`endif

//  -----------------------------------------
//  Statistics Module configuration registers
//  -----------------------------------------

register_map_statsn #(CNTWIDTH) U_MAPSTATSN (
          .reset_reg_clk(reset_reg_clk),
          .reg_clk(reg_clk),
          .reg_rd(reg_rd),
          .reg_wr(reg_wr),
          .reg_sel(reg_sel),
          .reg_data_in(reg_data_in),
          .stc_data_out(stc_data_out),  //  to read mux within regreadarb
          .stc_sel(stc_sel),            //  control read mux indicating a register of this module is accessed
          .sw_reset(sw_reset),
          .stc_saturate(stc_saturate),
          .stc_clearread(stc_clearread),
          .stc_clearall(stc_clearall),
          .stc_clearvalue(stc_clearvalue));

// copy the memory clear value into line clock domains. 
// Using a single DFF only as this is a static configuration, used during testing only anyway.

mtip_dffvec #(CNTWIDTH) U_SYCLRVALRX (
          .reset(reset_rxclk),
          .clk(rxclk),
          .i( stc_clearvalue ),
          .o( rx_stats_clearvalue ));

mtip_dffvec #(CNTWIDTH) U_SYCLRVALTX (
          .reset(reset_txclk),
          .clk(txclk),
          .i( stc_clearvalue ),
          .o( tx_stats_clearvalue ));

// --------------------------------------------------------
// transfer read data from line clocks to host clock domain
// --------------------------------------------------------
stats_regreadarb #(CNTWIDTH) U_REGREADARB (
          .reset_rxclk(reset_rxclk),
          .reset_txclk(reset_txclk),
          .reset_reg_clk(reset_reg_clk),
          .rxclk(rxclk),
          .txclk(txclk),
          .reg_clk(reg_clk),
          .reg_rd(reg_rd),
          .reg_sel(reg_sel),
          .stat_data_out(stat_data_out),
          .stat_rd(stat_rd),
          .stat_busy(stat_busy),
          .stc_data_out(stc_data_out),
          .stc_sel(stc_sel),                    // select stc_data_out muxing to stat_data_out
          //  Read rx stats (rxclk domain)
          .rx_stats_rd(rx_stats_rd),
          .rx_mreg_sel(rx_mreg_sel),
          .rx_stats_busy(rx_stats_busy),
          .rx_stats_rdata(rx_stats_rdata),      
          //  Read tx stats (txclk domain)
          .tx_stats_rd(tx_stats_rd),
          .tx_mreg_sel(tx_mreg_sel),
          .tx_stats_busy(tx_stats_busy),
          .tx_stats_rdata(tx_stats_rdata));

// --------------------------------------------------------
// Collect all RX statistics
// --------------------------------------------------------

// transfer configuration bits
mtip_xsync #(2) U_SYSTCRX (
          .data_in({stc_clearread, stc_saturate}),
          .reset(reset_rxclk),
          .clk(rxclk),
          .data_s({rx_stc_clearread, rx_stc_saturate}));

stats_collect_rx_xl #(CNTWIDTH,CNTSATURATEOPT) U_COLRX (
        `ifdef MTIP_SDPM_GEN_GLOBAL_RST
          .sdpm_core_reset(sdpm_core_reset),
          .sdpm_bist_i(sdpm_bist_i),
          .sdpm_bist_o(sdpm_bist_o0),
        `endif
          .reset(reset_rxclk),
          .clk(rxclk),
          .stc_clearread(rx_stc_clearread),     //  clock sync'ed
          .stc_saturate(rx_stc_saturate),
          .stats_rd(rx_stats_rd),               //  host access in line clock domain
          .mreg_sel(rx_mreg_sel),
          .stats_clear(rx_stats_clear),
          .stats_clearvalue(rx_stats_clearvalue),
          .stats_busy(rx_stats_busy),
          .stats_rdata(rx_stats_rdata),
          .frm_align_err(frm_align_err),
        `ifdef STAT_PFCCNT_ENA
          .rsv_stat_pfc(rsv_stat_pfc),
        `endif          
          .rsv_stat_val(rsv_stat_val),
          .rsv_stat(rsv_stat)
        `ifdef MTIPSTAT_MEM_EXTERNAL
           ,
           .rstm_raddr(rstm_raddr),
           .rstm_rden (rstm_rden ),
           .rstm_rdata(rstm_rdata),
           .rstm_wren (rstm_wren ),
           .rstm_waddr(rstm_waddr),
           .rstm_wdata(rstm_wdata)
        `endif
          );

// --------------------------------------------------------
// Collect all TX statistics, symmetric to RX statistics
// --------------------------------------------------------

// transfer configuration bits
mtip_xsync #(2+16) U_SYSTCTX (
          .data_in({tx_mtu, stc_clearread, stc_saturate}),
          .reset(reset_txclk),
          .clk(txclk),
          .data_s({tx_mtu_sy, tx_stc_clearread, tx_stc_saturate}));

stats_collect_txsym_xl 
        #(
        .CNTWIDTH(CNTWIDTH),
        .CNTSATURATEOPT(CNTSATURATEOPT)
`ifdef STAT_PFCCNT_ENA
        ,
        .PFC_PRIORITIES(PFC_PRIORITIES)
`endif
        ) 
U_COLTX (
        `ifdef MTIP_SDPM_GEN_GLOBAL_RST
          .sdpm_core_reset(sdpm_core_reset),
          .sdpm_bist_i(sdpm_bist_o0),
          .sdpm_bist_o(sdpm_bist_o1),
        `endif
          .reset(reset_txclk),
          .clk(txclk),
          .stc_clearread(tx_stc_clearread), //  clock sync'ed
          .stc_saturate(tx_stc_saturate),
          .tx_mtu(tx_mtu_sy),
          .stats_rd(tx_stats_rd), //  host access in line clock domain
          .mreg_sel(tx_mreg_sel),
          .stats_clear(tx_stats_clear),
          .stats_clearvalue(tx_stats_clearvalue),
          .stats_busy(tx_stats_busy),
          .stats_rdata(tx_stats_rdata),
        `ifdef STAT_PFCCNT_ENA
          .tsv_stat_pfc(tsv_stat_pfc),
        `endif          
          .tsv_stat_val(tsv_stat_val),
          .tsv_stat(tsv_stat)
        `ifdef MTIPSTAT_MEM_EXTERNAL
           ,
           .tstm_raddr(tstm_raddr),
           .tstm_rden (tstm_rden ),
           .tstm_rdata(tstm_rdata),
           .tstm_wren (tstm_wren ),
           .tstm_waddr(tstm_waddr),
           .tstm_wdata(tstm_wdata)
        `endif
          );

//  --------------------------------------------------------
//  Clear all statistics (software reset)
//  --------------------------------------------------------
//  clock domain crossing pulse generation
redge_ckxing U_RXCLEAR (
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .sig(stc_clearall),
          .reset_clk_o(reset_rxclk),
          .clk_o(rxclk),
          .sig_o(rx_stats_clear));

redge_ckxing U_TXCLEAR (
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .sig(stc_clearall),
          .reset_clk_o(reset_txclk),
          .clk_o(txclk),
          .sig_o(tx_stats_clear));

assign sw_reset_done = sw_reset; 

endmodule // module stats_topn_xl

